package cn.sc.summer.mybatis.config.transaction;

import cn.sc.summer.constant.mybatisplus.TransManagerConstant;
import cn.sc.summer.constant.project.ProjectConstant;
import com.atomikos.icatch.config.UserTransactionService;
import com.atomikos.icatch.config.UserTransactionServiceImp;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import java.util.Properties;

/**
 * 类名：全局事务管理器
 *
 * @author a-xin
 * @date 2024/7/11 11:28
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({AtomikosProperties.class})
@ConditionalOnClass({JtaTransactionManager.class, UserTransactionManager.class})
public class JtaTransactionManagerConfig {

    private static final String TM_XA_LOG_PATH = "./logs/tm/";

    @Value("${server.port}")
    private Integer PORT;

    /**
     * 配置jta日志文件，否则会报 LogException: Log already in use? tmlog in ./ 异常
     */
    @Primary
    @Bean(initMethod = "init", destroyMethod = "shutdownWait")
    @ConditionalOnMissingBean(UserTransactionService.class)
    public UserTransactionServiceImp userTransactionService(AtomikosProperties atomikosProperties) {
        Properties properties = new Properties();
        properties.setProperty("com.atomikos.icatch.tm_unique_name", ProjectConstant.SERVER_NAME + "-tm-" + PORT);
        properties.setProperty("com.atomikos.icatch.log_base_dir", TM_XA_LOG_PATH + ProjectConstant.SERVER_NAME + "-" + PORT);
        properties.putAll(atomikosProperties.asProperties());
        return new UserTransactionServiceImp(properties);
    }

    private static final String USER_TRANSACTION = "USER_TRANSACTION";
    private static final String ATOMIKOS_TRANSACTION_MANAGER = "ATOMIKOS_TRANSACTION_MANAGER";

    @Bean(name = USER_TRANSACTION)
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(30);
        return userTransactionImp;
    }

    @Bean(name = ATOMIKOS_TRANSACTION_MANAGER)
    public TransactionManager atomikosTransactionManager() {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        return userTransactionManager;
    }

    /**
     * jta全局事务管理器
     */
    @Primary
    @Bean(name = TransManagerConstant.JTA)
    @DependsOn({USER_TRANSACTION, ATOMIKOS_TRANSACTION_MANAGER})
    public PlatformTransactionManager activityTransactionManager() throws Throwable {
        log.info("==> Start initialization the TransactionManager: {}", TransManagerConstant.JTA);
        UserTransaction userTransaction = userTransaction();
        TransactionManager atomikosTransactionManager = atomikosTransactionManager();
        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }

}
